package com.hs.server.runnable;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.ByteString;
import com.hs.grpc.*;
import com.hs.server.config.MyConfig;
import com.hs.server.domain.*;
import com.hs.server.exception.GlobalException;
import com.hs.server.mapper.ShYcrzxxbMapper;
import com.hs.server.mapper.VehZnshzlzpxxMapper;
import com.hs.server.mapper.XbjcMapper;
import com.hs.server.service.*;
import com.hs.server.service.impl.JianyanHsServiceImpl;
import com.hs.server.utils.Base64Util;
import com.hs.server.utils.SpringContextUtil;
import io.grpc.StatusRuntimeException;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * @Description 资源审核控制模块
 * @Author: chenjiarui
 * @Date: 2021-07-19 8:57
 */
@Data
@RequiredArgsConstructor
@Slf4j
public class WorkCustomer implements Runnable {
    private VehQueuexxb vehQueuexxb;
    private ShResourcexx shResourcexx;
    private JianyanHsServiceImpl jianyanService;
    private ObjectMapper mapper = new ObjectMapper();
    private final VehZnshinfoService vehZnshinfoService = SpringContextUtil.getBean(VehZnshinfoService.class);
    private final VehQueuexxbService vehQueuexxbService = SpringContextUtil.getBean(VehQueuexxbService.class);
    //WorkCustomer非单例，需要观察这个对象跟@Autowired注入进来的对象是否同一个，不同对象调用更新操作synchronized方法不会产生互斥
    private final VehZnshzlzpxxService vehZnshzlzpxxService = SpringContextUtil.getBean(VehZnshzlzpxxService.class);
    private final ShResourcexxService shResourcexxService = SpringContextUtil.getBean(ShResourcexxService.class);
    private final ShItemConfigService shItemConfigService = SpringContextUtil.getBean(ShItemConfigService.class);
    private final ShResourcexxRecordService shResourcexxRecordService = SpringContextUtil.getBean(ShResourcexxRecordService.class);
    private final ShYcrzxxbMapper shYcrzxxbMapper = SpringContextUtil.getBean(ShYcrzxxbMapper.class);
    private final MyConfig myConfig = SpringContextUtil.getBean(MyConfig.class);
    private final XbjcMapper xbjcMapper = SpringContextUtil.getBean(XbjcMapper.class);
    private final String imgPath = myConfig.imgPath;
    private final int compareThreshold = myConfig.compareThreshold;
    private final VehAiauditinfoService vehAiauditinfoService = SpringContextUtil.getBean(VehAiauditinfoService.class);
    private final VehZnshzlzpxxMapper vehZnshzlzpxxMapper = SpringContextUtil.getBean(VehZnshzlzpxxMapper.class);

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    private SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMMdd");
    private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");

    // 定义常量
    private static final int RESULT_SUCCESS = 1; // 审核通过
    private static final int RESULT_MANUAL_REVIEW = 4; // 建议人工
    private static final int RESULT_FAILED = 5; // 审核不通过
    private static final int RESULT_SERVER_ERROR = 0; // 服务器出错，启用检测重连机制
    private static final int RESULT_EXCEPTION = -1; // 系统异常

    private static final String QUEUE_STATUS_IN_REVIEW = "1"; // 审核中
    private static final String QUEUE_STATUS_REVIEWED = "4"; // 已审核
    private static final String QUEUE_STATUS_ERROR = "2"; // 审核出错

    private static final String SHZT_PASSED = "1";
    private static final String SHZT_FAILED = "5";
    private static final String SHZT_MANUAL = "4";

    private static final String SERVER_STATUS_IDLE = "1"; // 服务器空闲

    private static final int RESULT_QUALIFIED = 1; // 通过
    private static final int RESULT_UNQUALIFIED = 5; // 不通过

    // 创建一个ReentrantLock对象
    private final ReentrantLock lock = new ReentrantLock();

    public WorkCustomer(VehQueuexxb vehQueuexxb,ShResourcexx shResourcexx,JianyanHsServiceImpl jianyanService){
        this.vehQueuexxb = vehQueuexxb;
        this.shResourcexx = shResourcexx;
        this.jianyanService = jianyanService;
    }
    @SneakyThrows
    @Override
    public void run() {
        lock.lock();  // 加锁
        log.info("服务器【"+shResourcexx.getIpdz() + "-" + shResourcexx.getShxcbh()+"】"+"获取到"+vehQueuexxb.getLsh()+"-"+vehQueuexxb.getZpzl()+"的审核权");
        //存储本次审核的结果
        int workResult = inspectExamine(vehQueuexxb,shResourcexx);
        statistics(workResult);
        lock.unlock();  // 释放锁
    }

    private void statistics(int workResult){
        synchronized (WorkCustomer.class){
            if (workResult != 0 && workResult!=-1) {//有东西返回则证明有调用过服务器
                log.info("服务器【"+shResourcexx.getIpdz()+ "-" + shResourcexx.getShxcbh()+"】"+"审核"+vehQueuexxb.getLsh()+"-"+vehQueuexxb.getZpzl()+"完成！");
            }
            //服务器出错，需要启动重连机制
            if (workResult == 0) {
                //todo 算法服务器挂了，将该算法服务器zt改成异常，该条作业审核状态重置为0，已让它下次能重新审
                log.error("服务器【"+shResourcexx.getIpdz()+ "-" + shResourcexx.getShxcbh()+"】"+"审核"+vehQueuexxb.getLsh()+"-"+vehQueuexxb.getZpzl()+"出错！已将该服务器状态置为异常，请人工检查后再将其状态置为正常");
                todoServiceExCeption(vehQueuexxb,shResourcexx);
            }
            //程序内部错误
            if (workResult==-1){
                log.error(vehQueuexxb.getLsh()+"-"+vehQueuexxb.getZpzl()+"审核过程中出现程序内部错误！");
            }
        }
    }

    /**
     * @param vehQueuexxb
     * @return 1-审核通过 4-建议人工 5-审核不通过 0-服务器出错，启用检测重连机制
     */
    //@Transactional(rollbackFor = Exception.class)
    public int inspectExamine(VehQueuexxb vehQueuexxb, ShResourcexx shResourcexx) {
        String lsh = vehQueuexxb.getLsh();
        String zpzl = vehQueuexxb.getZpzl();
        String parseGrpcBack = null;

        try {
            VehZnshinfo vehZnshinfo = vehZnshinfoService.GetVehZnshinfoByLsh(lsh);
            VehZnshzlzpxx vehZnshzlzpxx = vehZnshzlzpxxService.GetVehZnshzlzpxx(lsh, zpzl);

            validatePreconditions(vehZnshinfo, vehZnshzlzpxx, vehQueuexxb, shResourcexx);
            parseGrpcBack = callGrpcService(shResourcexx, vehQueuexxb, vehZnshinfo, vehZnshzlzpxx);
            return processReviewResult(lsh, zpzl, parseGrpcBack, vehZnshzlzpxx, vehZnshinfo);

        } catch (StatusRuntimeException e) {
            log.error("inspectExamine: 【gRPC服务调用异常】流水号:{} 照片种类:{} 异常信息:{}", lsh, zpzl, e.getMessage(), e);
            handleGrpcException(vehQueuexxb, shResourcexx, lsh, e);
            return RESULT_SERVER_ERROR;
        } catch (GlobalException e) {
            log.error("inspectExamine: 【业务异常】流水号:{} 照片种类:{} 异常信息:{}", lsh, zpzl, e.getMessage(), e);
            insertShYcrzxxb(lsh, shResourcexx, e.getMessage());
            return RESULT_EXCEPTION; // 或者根据业务需求返回其他错误码
        } catch (Exception e) {
            log.error("inspectExamine: 【系统异常】流水号:{} 照片种类:{} 异常信息:{}", lsh, zpzl, e.getMessage(), e);
            handleSystemException(vehQueuexxb, shResourcexx, lsh, e);
            return RESULT_EXCEPTION;
        } finally {
            shutdownGrpcChannel();
            setServerIdle(shResourcexx);
        }
    }

    /**
     * 验证车辆审核信息和照片信息是否存在
     * @param vehZnshinfo
     * @param vehZnshzlzpxx
     * @param vehQueuexxb
     * @param shResourcexx
     */
    private void validatePreconditions(VehZnshinfo vehZnshinfo, VehZnshzlzpxx vehZnshzlzpxx, VehQueuexxb vehQueuexxb, ShResourcexx shResourcexx) {
        if (vehZnshinfo == null) {
            String errorMsg = String.format("流水号[%s]的车辆审核信息为空!", vehQueuexxb.getLsh());
            log.error("validatePreconditions: {}", errorMsg);
            insertShYcrzxxb(vehQueuexxb.getLsh(), shResourcexx, errorMsg);
            throw new GlobalException(errorMsg);
        }
        if (vehZnshzlzpxx == null) {
            String errorMsg = String.format("流水号[%s]-照片种类[%s]的车辆照片信息为空!", vehQueuexxb.getLsh(), vehQueuexxb.getZpzl());
            log.error("validatePreconditions: {}", errorMsg);
            insertShYcrzxxb(vehQueuexxb.getLsh(), shResourcexx, errorMsg);
            throw new GlobalException(errorMsg);
        }
    }

    /**
     * 更新队列状态
     * @param vehQueuexxb
     * @param status
     */
    private void updateQueueStatus(VehQueuexxb vehQueuexxb, String status) {
        vehQueuexxb.setZt(status);
        vehQueuexxbService.updateVehQueuexxb(vehQueuexxb);
        log.info("updateQueueStatus: 流水号:{} 照片种类:{} 队列状态更新为:{}", vehQueuexxb.getLsh(), vehQueuexxb.getZpzl(), status);
    }

    /**
     * 更新照片的开始审核时间
     * @param vehZnshzlzpxx
     * @throws ParseException
     */
    private void updatePhotoReviewStartTime(VehZnshzlzpxx vehZnshzlzpxx){
        try {
            vehZnshzlzpxx.setShkssj(formatter.parse(formatter.format(new Date())));
        } catch (ParseException e) {
            log.error("updatePhotoReviewStartTime: 流水号:{} 照片种类:{} 更新照片审核开始时间出错！", vehZnshzlzpxx.getLsh(), vehZnshzlzpxx.getZpzl(), e);
        }
    }

    /**
     * 更新照片的结束审核时间
     * @param vehZnshzlzpxx
     * @throws ParseException
     */
    private void updatePhotoReviewEndTime(VehZnshzlzpxx vehZnshzlzpxx){
        try {
            vehZnshzlzpxx.setShjssj(formatter.parse(formatter.format(new Date())));
        } catch (ParseException e) {
            log.error("updatePhotoReviewEndTime: 流水号:{} 照片种类:{} 更新照片审核结束时间出错！", vehZnshzlzpxx.getLsh(), vehZnshzlzpxx.getZpzl(), e);
        }
    }

    /**
     * 调用Grpc服务
     * @param shResourcexx
     * @param vehQueuexxb
     * @param vehZnshinfo
     * @param zpurl
     * @param shlb
     * @return
     */
    public String callGrpcService(ShResourcexx shResourcexx, VehQueuexxb vehQueuexxb, VehZnshinfo vehZnshinfo, VehZnshzlzpxx vehZnshzlzpxx) {
        String zpurl = vehZnshzlzpxx.getZpurl();
        //synchronized (WorkCustomer.class) {
            updateQueueStatus(vehQueuexxb, QUEUE_STATUS_IN_REVIEW);
            updatePhotoReviewStartTime(vehZnshzlzpxx);//地址引用，会直接赋值出来
            String parseGrpcBack = parseGrpc(shResourcexx, vehQueuexxb, vehZnshinfo, zpurl);
            if (StringUtils.isNotBlank(parseGrpcBack) && parseGrpcBack.equals("-1")) {
                log.error("callGrpcService: 流水号:{} 照片种类:{} Grpc接口调用返回-1，表示服务器挂了", vehQueuexxb.getLsh(), vehQueuexxb.getZpzl());
                throw new StatusRuntimeException(io.grpc.Status.UNAVAILABLE.withDescription("gRPC server returned -1"));
            }
            updateReviewCount(shResourcexx);
            updateQueueStatus(vehQueuexxb, QUEUE_STATUS_REVIEWED);
            updatePhotoReviewEndTime(vehZnshzlzpxx);//地址引用，会直接赋值出来
            return parseGrpcBack;
        //}
    }

    /**
     * 更新服务器资源成功审核次数
     * @param shResourcexx
     */
    private void updateReviewCount(ShResourcexx shResourcexx) {
        synchronized (WorkCustomer.class) {
            int shzcs = shResourcexxService.getShzcs(shResourcexx.getFwqbh());
            shzcs++;
            shResourcexx.setShzcs(String.valueOf(shzcs));
            shResourcexxRecordService.shzcsIncrease(shResourcexx);
            log.info("updateReviewCount: 服务器[{}]审核总次数更新为:{}", shResourcexx.getFwqbh(), shzcs);
        }
    }

    /**
     * 更新GRPC服务调用异常导致服务器资源失败审核次数
     * @param vehQueuexxb
     * @param shResourcexx
     * @param lsh
     * @param e
     */
    private void handleGrpcException(VehQueuexxb vehQueuexxb, ShResourcexx shResourcexx, String lsh,StatusRuntimeException e) {
        synchronized (WorkCustomer.class) {
            int clcs = shResourcexxService.getclcs(shResourcexx.getFwqbh());
            clcs++;
            shResourcexx.setClcs(String.valueOf(clcs));
            shResourcexxRecordService.clcsIncrease(shResourcexx);
            log.warn("handleGrpcException: 服务器[{}]重连次数更新为:{}", shResourcexx.getFwqbh(), clcs);
        }
        // 仅当队列中仍存在该流水号的作业时才更新状态，避免空指针
        if (vehQueuexxbService.getVehQueuexxb(lsh) != null && !vehQueuexxbService.getVehQueuexxb(lsh).isEmpty()) {
            updateQueueStatus(vehQueuexxb, QUEUE_STATUS_ERROR);
        }
        insertShYcrzxxb(lsh, shResourcexx, "gRPC服务调用异常: " + e.getMessage());
    }

    /**
     * 更新系统异常导致服务器资源失败审核次数
     * @param vehQueuexxb
     * @param shResourcexx
     * @param lsh
     * @param e
     */
    private void handleSystemException(VehQueuexxb vehQueuexxb, ShResourcexx shResourcexx, String lsh, Exception e) {
        synchronized (WorkCustomer.class) {
            int clcs = shResourcexxService.getclcs(shResourcexx.getFwqbh());
            clcs++;
            shResourcexx.setClcs(String.valueOf(clcs));
            shResourcexxRecordService.clcsIncrease(shResourcexx);
            log.warn("handleSystemException: 服务器[{}]重连次数更新为:{}", shResourcexx.getFwqbh(), clcs);
        }
        if (vehQueuexxbService.getVehQueuexxb(lsh) != null && !vehQueuexxbService.getVehQueuexxb(lsh).isEmpty()) {
            updateQueueStatus(vehQueuexxb, QUEUE_STATUS_ERROR);
        }
        insertShYcrzxxb(lsh, shResourcexx, "系统异常: " + e.getMessage());
    }

    /**
     * 关闭Grpc通道
     */
    private void shutdownGrpcChannel() {
        try {
            if (jianyanService != null && jianyanService.getChannel() != null) {
                jianyanService.getChannel().shutdown().awaitTermination(3, TimeUnit.SECONDS);
                //log.info("shutdownGrpcChannel: gRPC通道已关闭。");
            }
        } catch (InterruptedException e) {
            log.error("shutdownGrpcChannel: 关闭gRPC通道时被中断", e);
            Thread.currentThread().interrupt(); // 恢复中断状态
        }
    }

    /**
     * 设置服务器空闲状态的方法

 * 该方法用于将指定服务器的状态设置为空闲，并更新数据库中的记录
     * @param shResourcexx 服务器资源对象，包含服务器的相关信息
     */
    private void setServerIdle(ShResourcexx shResourcexx) {
    // 使用同步代码块确保线程安全，锁定WorkCustomer类的Class对象
        synchronized (WorkCustomer.class) {
        // 设置服务器状态为空闲
            shResourcexx.setSfkx(SERVER_STATUS_IDLE);
        // 更新服务器资源信息到数据库
            shResourcexxService.updateResourcexx(shResourcexx);
        // 记录日志，输出服务器状态变更信息
            log.info("setServerIdle: 服务器[{}]状态设置为空闲。", shResourcexx.getFwqbh());
        }
    }

    /**
     * 解析grpc识别返回信息
     * @param lsh
     * @param zpzl
     * @param parseGrpcBack
     * @param vehZnshzlzpxx
     * @param vehZnshinfo
     * @return
     */
    private int processReviewResult(String lsh, String zpzl, String parseGrpcBack, VehZnshzlzpxx vehZnshzlzpxx, VehZnshinfo vehZnshinfo) {
        String btgjyx = "";
        String grpcBack = "";
        String grpcRequest = "";

        if (StringUtils.isNotBlank(parseGrpcBack)) {
            String[] res = parseGrpcBack.split("---##---");
            if (res.length >= 3) {
                btgjyx = res[0];
                grpcBack = res[1];
                grpcRequest = res[2];
                if (grpcBack.equals("{}")){
                    log.error("ocr加工程序返回可能报错，流水号：{}，照片种类：{}",lsh,zpzl);
                    //log.error("ocr加工程序报错，直接置服务器资源为异常，流水号：{}，照片种类：{}",lsh,zpzl);
                    //return RESULT_SERVER_ERROR;//ocr加工程序报错，直接致服务器资源为异常
                }
            } else {
                log.warn("processReviewResult: parseGrpcBack格式不正确，流水号:{} 照片种类:{} 返回值:{}", lsh, zpzl, parseGrpcBack);
            }
        }

        if (xbjcMapper.getZpshbjByZpzl(lsh,zpzl).equals("0")) {//可能在审核过程中重拍了，则本次审核结果不写入，默认返回
            xbjcMapper.updateVehFlowYshbj(lsh,"0");
            log.info("{}-{}可能在审核过程中重拍了，则本次审核结果不写入，默认返回",lsh,zpzl);
            return 1;
        }
        //更新照片相关信息
        vehZnshzlzpxx = updatePhotoReviewDetails(vehZnshinfo,vehZnshzlzpxx, btgjyx, grpcBack,grpcRequest);
        int shzt2 = Integer.parseInt(vehZnshzlzpxx.getShzt2());
        //添加审核结果到新版数据库veh_aiauditinfo中
        saveVehAiauditinfo(lsh,zpzl,grpcBack,shzt2,vehZnshzlzpxx.getShbtgyy2(),vehZnshinfo);
        //更新新版数据库照片表zpshbj
        xbjcMapper.updateZpshbjByZpzl(lsh,shzt2==1?"1":"5",zpzl);

//        String lszt = xbjcMapper.getLszt(lsh);
//        int unreviewedCount = xbjcMapper.getUnreviewedCount(lsh);
//        if ((lszt.equals("4") || lszt.equals("5")) && unreviewedCount==0) {
//            log.info("processReviewResult: 流水号[{}]所有照片已审核完成，开始判定整车审核结果。", lsh);
//            return finalizeVehicleReview(lsh, vehZnshinfo);
//        }
        return shzt2;
    }

    /**
     * 保存新版照片审核信息
     * @param jylsh
     * @param zpzl
     * @param sbnr
     * @param shzt
     */
    private void saveVehAiauditinfo(String jylsh,String zpzl,String sbnr,Integer shzt,String shbtgyy2,VehZnshinfo vehZnshinfo){
        VehAiauditinfo vehAiauditinfo = new VehAiauditinfo();
        vehAiauditinfo.setJylsh(jylsh);
        vehAiauditinfo.setZpzl(zpzl);
        vehAiauditinfo.setSbnr(sbnr);
        vehAiauditinfo.setShjg(shzt == 1 ? "1" : "2");
        vehAiauditinfo.setSfzzbz("1");
        vehAiauditinfo.setJycs(vehZnshinfo.getJycs());
        if (shzt == 5){
            vehAiauditinfo.setZp(Base64Util.imageUrlToBase64(myConfig.getImgPath()+jylsh+"_"+zpzl+".jpg"));
        }
        if (StringUtils.isNotBlank(shbtgyy2))
            vehAiauditinfo.setBtgyy(shbtgyy2);
        vehAiauditinfoService.saveByJylshAndZpzl(vehAiauditinfo);
    }

    public String getJyxMc(String btgjyx){
        StringBuilder sb = new StringBuilder();
        String[] jyxs = btgjyx.split(",");
        for (String jyx : jyxs){
            sb.append(shItemConfigService.getZhJyx(jyx));
        }
        return sb.toString();
    }

    /**
     * 更新照片审核信息
     * @param vehZnshzlzpxx
     * @param shzt
     * @param btgjyx
     * @param grpcBack
     */
    private VehZnshzlzpxx updatePhotoReviewDetails(VehZnshinfo vehZnshinfo,VehZnshzlzpxx vehZnshzlzpxx, String btgjyx, String grpcBack,String grpcRequest) {
        int zs = vehZnshinfo.getZs();
        //获取照片的通过项
        List<String> jyxList = Arrays.asList(vehZnshzlzpxx.getJyx().split(","));//所有检验项
        List<String> btgjyxList = Arrays.asList(btgjyx.split(","));//不通过项
        List<String>  tgjyxList = (List<String>) CollectionUtils.disjunction(jyxList, btgjyxList);
        String shbtgyy = Optional.ofNullable(btgjyx)
                .filter(StringUtils::isNotBlank)
                .map(this::getZhJyx)
                .orElse("");
        vehZnshzlzpxx.setShbtgyy(shbtgyy);
        vehZnshzlzpxx.setShbtgyy2(shbtgyy);
        if (StringUtils.isNotBlank(grpcBack) && grpcBack.contains("异常】")){
            log.error("{}-{}审核出错：{}",vehZnshzlzpxx.getLsh(),vehZnshzlzpxx.getZpzl(),grpcBack);
            vehZnshzlzpxx.setSbnr(grpcBack);
            vehZnshzlzpxx.setShzt("-1");//审核出错
            vehZnshzlzpxx.setShzt2("-1");//审核出错
            vehZnshzlzpxx.setRequest(grpcRequest);
            vehZnshzlzpxxService.UpdateZnshzlzpxx(vehZnshzlzpxx);
            return vehZnshzlzpxx;
        }

        vehZnshzlzpxx = handleLinkGW(vehZnshzlzpxx,Arrays.asList("0111","0112"),Arrays.asList("jy_001_002","jy_002_002"),"[三脚架目标检测-是否存在]",null);
        vehZnshzlzpxx = handleLinkGW(vehZnshzlzpxx,Arrays.asList("0321","0352"),Arrays.asList("jy_031_001","jy_041_001"),"[车灯-是否亮]",null);
        vehZnshzlzpxx = handleLinkGW(vehZnshzlzpxx,Arrays.asList("A110","A111"),Arrays.asList("jy_080_001","jy_081_001"),"[车牌识别-与实际值比对]",null);
        vehZnshzlzpxx = handleLinkGW(vehZnshzlzpxx,Arrays.asList("0111","0112"),Arrays.asList("jy_001_003","jy_002_003"),"[车身颜色-与实际值比对]",null);
        //关联灯光照片
        vehZnshzlzpxx = handleLinkGW(vehZnshzlzpxx,Arrays.asList("0321","0352"),Arrays.asList("jy_031_002","jy_041_002"),"[车牌号-与实际值比对]","H");
        //关联外廓照片
        vehZnshzlzpxx = handleLinkGW(vehZnshzlzpxx,Arrays.asList("0360","0361"),Arrays.asList("jy_063_002","jy_064_002"),"[车牌识别-与实际值比对]","M");
        //关联整备质量照片
        vehZnshzlzpxx = handleLinkGW(vehZnshzlzpxx,Arrays.asList("0362","0363"),Arrays.asList("jy_093_001","jy_094_001"),"[车牌号-与实际值比对]","Z");
        //关联一二轴制动照片
        List<String> zdzpzlList = new ArrayList<>();//制动
        List<String> zdjyxKeyList = new ArrayList<>();//制动

        zdzpzlList.add("0322");
        zdjyxKeyList.add("jy_037_002");
        zdzpzlList.add("0348");
        zdjyxKeyList.add("jy_038_002");

        List<String> lzzpzlList = new ArrayList<>();//轮重
        List<String> lzjyxKeyList = new ArrayList<>();//轮重
        //车牌
        lzzpzlList.add("A302");
        lzjyxKeyList.add("jy_088_001");
        lzzpzlList.add("A303");
        lzjyxKeyList.add("jy_089_001");

        if (zs==3){
            //制动车牌
            zdzpzlList.add("0349");
            zdjyxKeyList.add("jy_039_002");
            //轮重车牌
            lzzpzlList.add("A304");
            lzjyxKeyList.add("jy_090_001");
        }
        if (zs==4){
            //制动车牌
            zdzpzlList.add("0350");
            zdjyxKeyList.add("jy_040_002");
            //轮重车牌
            lzzpzlList.add("A305");
            lzjyxKeyList.add("jy_091_001");
        }
        if (zs==5){
            //制动车牌
            zdzpzlList.add("0354");
            zdjyxKeyList.add("jy_043_002");
            //轮重车牌
            lzzpzlList.add("A306");
            lzjyxKeyList.add("jy_092_001");
        }
        vehZnshzlzpxx = handleLinkGW(vehZnshzlzpxx,zdzpzlList,zdjyxKeyList,"[车牌号-与实际值比对]","B");

        //关联一二轴称重工位照片
        vehZnshzlzpxx = handleLinkGW(vehZnshzlzpxx,lzzpzlList,lzjyxKeyList,"[车牌号-与实际值比对]","W");

        vehZnshzlzpxx.setShtgx(
                Optional.ofNullable(tgjyxList)
                .orElse(Collections.emptyList())
                .stream()
                .map(this::getZhJyx)
                .filter(StringUtils::isNotBlank) // 过滤 null 和 空白字符串
                .collect(Collectors.joining(",")));
        String shzt2 = StringUtils.isNotBlank(vehZnshzlzpxx.getShbtgyy2())?"5":"1";
        String shzt = StringUtils.isNotBlank(vehZnshzlzpxx.getShbtgyy())?"5":"1";
        vehZnshzlzpxx.setShzt(shzt);
        vehZnshzlzpxx.setShzt2(shzt2);
        vehZnshzlzpxx.setRequest(grpcRequest);
        try {
            JsonNode rootNode = mapper.readTree(grpcBack);
            JsonNode originalDataNode = rootNode.get("original_data");
            JsonNode originalRequestDataNode = rootNode.get("original_request_data");
            if (originalDataNode!=null){
                String originalDataNodeStr = originalDataNode.toPrettyString();
                vehZnshzlzpxx.setOcr(originalDataNodeStr);
                vehZnshzlzpxx.setSbnr(grpcBack.replace(originalDataNodeStr,""));
            }else {
                vehZnshzlzpxx.setOcr("");
                vehZnshzlzpxx.setSbnr(grpcBack);
            }
            if (originalRequestDataNode!=null){
                String originalRequestDataStr = originalRequestDataNode.toPrettyString();
                vehZnshzlzpxx.setOriginalRequestData(originalRequestDataStr);
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        vehZnshzlzpxxService.UpdateZnshzlzpxx(vehZnshzlzpxx);
        log.info("updatePhotoReviewDetails: 流水号:{} 照片种类:{} 审核状态:{} 不通过原因:{},修订后审核状态:{},修订后不通过原因:{}",
                vehZnshzlzpxx.getLsh(), vehZnshzlzpxx.getZpzl(), shzt, vehZnshzlzpxx.getShbtgyy(),shzt2,vehZnshzlzpxx.getShbtgyy2());
        return vehZnshzlzpxx;
    }

    /**
     * 处理工位照片车牌的关联（只在最后一张照片处理时进行修订）
     */
    private VehZnshzlzpxx handleLinkGW(VehZnshzlzpxx vehZnshzlzpxx, List<String> zpzlList, List<String> jyxKeyList, String tripodKey, String gwxm) {
        //处理的照片无需关联，则跳过处理
        if (!zpzlList.contains(vehZnshzlzpxx.getZpzl())) {
            return vehZnshzlzpxx;
        }
        List<VehZnshzlzpxx> linkList = vehZnshzlzpxxMapper.getVehZnshzlzpxxList(vehZnshzlzpxx.getLsh(), zpzlList);
        // 先移除掉本身这张（按 zpzl 匹配）
        linkList = linkList.stream()
                .filter(item -> !vehZnshzlzpxx.getZpzl().equals(item.getZpzl()))
                .collect(Collectors.toList());

        // 再添加本身这张照片（保持完整性并确保当前照片最后处理）
        linkList.add(vehZnshzlzpxx);
        if (linkList.size() == zpzlList.size()) {
            //判断时间间隔，决定是否关联
            int count = xbjcMapper.judgeTime(zpzlList,vehZnshzlzpxx.getLsh());
            if (count>0){
                log.info("照片：[{}] 与其他照片时间间隔大于60秒，不关联", vehZnshzlzpxx.getZpzl());
                return vehZnshzlzpxx;
            }

            log.info("{}进入处理工位照片车牌关联方法，流水号：{}，照片种类集合：{}，校验项：{}，tripodKey：{}，工位项：{}", vehZnshzlzpxx.getZpzl(),vehZnshzlzpxx.getLsh(), zpzlList, jyxKeyList, tripodKey, gwxm);

            boolean tripodNotInAny = false;//关联项是否不存在于某张照片，是则默认其它照片该项也通过

            for (VehZnshzlzpxx link : linkList) {
                log.info("处理照片：[{}]，审核状态：{}，检验项：{}", link.getZpzl(), link.getShzt(), link.getJyx());
                if (!Arrays.asList("1", "5").contains(link.getShzt()) && !link.getZpzl().equals(vehZnshzlzpxx.getZpzl())) {//本身传进来的照片还没有审核状态
                    log.info("跳过未审核照片：[{}]", link.getZpzl());
                    continue;
                }

                String linkJyx = Optional.ofNullable(link.getJyx()).orElse("");
                boolean enabled = jyxKeyList.stream().anyMatch(linkJyx::contains);//是否开启该审核项

                if (enabled) {
                    List<String> linkYyList = StringUtils.isNotBlank(link.getShbtgyy2()) ?
                            new ArrayList<>(Arrays.asList(link.getShbtgyy2().split(","))) : new ArrayList<>();
                    log.info("照片：[{}] 审核不通过原因：{}", link.getZpzl(), linkYyList);

                    if (!linkYyList.contains(tripodKey)) {
                        tripodNotInAny = true;
                    }
                } else {
                    log.info("照片：[{}] 未启用目标检验项，跳过", link.getZpzl());
                }
            }

            for (VehZnshzlzpxx link : linkList) {
                String linkZpzl = link.getZpzl();
                List<String> linkYyList = StringUtils.isNotBlank(link.getShbtgyy2()) ?
                        new ArrayList<>(Arrays.asList(link.getShbtgyy2().split(","))) : new ArrayList<>();

                String linkJyx = Optional.ofNullable(link.getJyx()).orElse("");
                boolean enabled = jyxKeyList.stream().anyMatch(linkJyx::contains);

                if (enabled) {
                    boolean changed = false;
                    if (tripodNotInAny) {
                        log.info("照片：[{}]-{}-判断-{}，进行剔除", linkZpzl,linkYyList,tripodKey);
                        linkYyList = linkYyList.stream().filter(v -> !tripodKey.equals(v)).collect(Collectors.toList());
                        changed = true;
                    }

                    if (changed) {
                        String newShzt = linkYyList.isEmpty() ? "1" : "5";
                        log.info("更新照片：[{}] 审核状态为：{}，原因为：{}", linkZpzl, newShzt, linkYyList);
                        vehZnshzlzpxxService.updateLinkedShzt(link.getLsh(), newShzt, String.join(",", linkYyList), linkZpzl);
                        xbjcMapper.updateShjg(link.getLsh(), newShzt.equals("5") ? "2" : "1", String.join(",", linkYyList), linkZpzl);
                        xbjcMapper.updateZpshbjByZpzl(link.getLsh(), newShzt.equals("5") ? "2" : "1", linkZpzl);
                    }

                    if (linkZpzl.equals(vehZnshzlzpxx.getZpzl())) {
                        vehZnshzlzpxx.setShbtgyy2(String.join(",", linkYyList));
                    }
                }
            }
        }

        return vehZnshzlzpxx;
    }


        /**
         * 判断该图片是否合格  0——未审核 1——通过 4——建议人工 5——不通过
         *
         * @param btgjyx 不通过检验项
         * @return 1-通过 5-不通过
         */
    private int isQualified(String btgjyx) {
        return StringUtils.isNotBlank(btgjyx) ? RESULT_UNQUALIFIED : RESULT_QUALIFIED;
    }

    /**
     * 获取待检验项中文
     * @param jyx 检验项，多个以逗号分隔
     * @return 中文检验项，多个以逗号分隔
     */
    private String getZhJyx(String jyx) {
        if (StringUtils.isBlank(jyx)) {
            return "";
        }
        return Arrays.stream(jyx.split(","))
                .filter(StringUtils::isNotBlank) // 过滤空字符串
                .map(shItemConfigService::getZhJyx) // 转换为中文
                .collect(Collectors.joining(",")); // 重新用逗号连接
    }

    /**
     * 根据zpzl匹配不同的grpc审核方法
     * @param vehQueuexxb 作业数据
     * @param vehZnshinfo 车辆信息
     * @param zpurl       车辆照片
     * @return 不合格的检验项
     */
    public String parseGrpc(ShResourcexx shResourcexx,VehQueuexxb vehQueuexxb,VehZnshinfo vehZnshinfo, String zpurl) {
        String jyx = vehQueuexxb.getJyx();
        String zpzl = vehQueuexxb.getZpzl();//照片种类
        if (!zpurl.contains("http"))
            zpurl = imgPath+zpurl;
        switch (zpzl) {
            case "0111"://车辆左前方斜视45度照片
            case "0112"://车辆右后方斜视45度照片
                return callCheckAppearance(jyx, vehZnshinfo , zpurl);
            case "0113"://车辆识别代号照片
                return callCheckVin(shResourcexx,jyx, vehZnshinfo, zpurl);
            case "0115"://车厢内部照片
                return callCheckVanInside(shResourcexx,jyx,vehZnshinfo,zpurl);
            case "0116"://灭火器照片
                return callCheckFireExtinguisher(shResourcexx,jyx,vehZnshinfo,zpurl);
            case "0117"://应急锤照片
                return callCheckEmergencyHammer(shResourcexx,jyx,vehZnshinfo,zpurl);
            case "0118"://行驶记录装置照片
                return callCheckDriverRecorder(shResourcexx,jyx,vehZnshinfo,zpurl);
            case "0119"://发动机号或柔性标签
                return callCheckEngineNumber(shResourcexx,jyx,vehZnshinfo,zpurl);
            case "0126"://校车停车指示标志牌照片
                return callCheckBusStopSign(shResourcexx,jyx,vehZnshinfo,zpurl);
            case "0130"://辅助制动系统
                return callCheckGearLever(shResourcexx,jyx,vehZnshinfo,zpurl);
            case "0132"://发动机舱自动灭火装置
                return callCheckFireExtinguisher(shResourcexx,jyx,vehZnshinfo,zpurl);
            case "0138"://校车、卧铺客车的车内外录像监控系统
                return callCheckVideoRecordingSystem(shResourcexx,jyx,vehZnshinfo,zpurl);
            case "0140"://教练车副制动踏板
                return callCheckPassengerPedal(shResourcexx,jyx,vehZnshinfo,zpurl);
            case "0136"://左前轮胎规格型号
            case "0152"://前轮胎胎纹
            case "0153"://后轮胎胎纹
            case "0154"://右前轮胎规格型号
            case "0155"://左后轮胎规格型号
            case "0156"://右后轮胎规格型号
                return callCheckTyreSpecification(shResourcexx,jyx,vehZnshinfo,zpurl);
            case "0157"://安全带
                return callCheckSeatBelt(shResourcexx,jyx,vehZnshinfo, zpurl);
            case "0163"://危险货物运输车标志
                return callCheckDangerousGoods(shResourcexx,jyx,vehZnshinfo, zpurl);
            case "0169"://发动机灭火器
                return callCheckCarExtinguisher(shResourcexx,jyx,vehZnshinfo, zpurl);
            case "A104": //手动机械断电开关
                return callCheckEmergencySwitch(shResourcexx,jyx,vehZnshinfo, zpurl);
            case "0175"://透光检测仪读数
                return callCheckInstrument(shResourcexx,jyx,vehZnshinfo, zpurl);
            case "0158":
            case "A111"://车辆正后方照片
                return callCheckVehRear(shResourcexx,jyx,vehZnshinfo, zpurl);
            case "A110"://车辆正前上方照片
                return callCheckVehFront(shResourcexx,jyx,vehZnshinfo, zpurl);
            case "0201": //机动车行驶证
            case "0287"://行驶证正面
                return callCheckVehicleLicense(shResourcexx, jyx, vehZnshinfo, zpurl);
            case "0288"://行驶证背面
                return callCheckVehicleLicenseBack(shResourcexx, jyx, vehZnshinfo, zpurl);
            case "0202"://机动车牌证申请表
                return callCheckLicenseApplicationForm(shResourcexx,jyx, vehZnshinfo, zpurl);
            case "0203"://机动车交通事故责任强制保险凭证
                return callCheckInsurancePolicy(shResourcexx,jyx, vehZnshinfo, zpurl);
            case "0204"://机动车安全技术检验报告单
                return callCheckInspectionReport(shResourcexx,jyx, vehZnshinfo, zpurl);
            case "0293"://检验表（人工检验部分）1
                return callCheckInspectionFormManual(shResourcexx,jyx,vehZnshinfo, zpurl, null);
            case "0289"://检验表（人工检验部分）2
                return callCheckInspectionFormManual(shResourcexx,jyx,vehZnshinfo,null, zpurl);
//            case "0206"://车船税纳税或者免税证明
//                return null;
//            case "0207"://委托核发检验合格标志通知书
            case "0208"://代理人授权书
                return callCheckAttorneyLetter(shResourcexx,jyx, vehZnshinfo, zpurl);
//            case "0286"://仪器检验报告
//                return callCheckSafetyTechnicalInspectionFormInstrument(shResourcexx,jyx, vehZnshinfo, zpurl);
            case "0290"://机动车登记证书
                return null;
            case "0210"://机动车排放污染检测报告单首页
                return callCheckExhaustDetectionReport(shResourcexx,jyx, vehZnshinfo, zpurl,null);
            case "0209"://机动车排放污染检测报告单未页
                return callCheckExhaustDetectionReport(shResourcexx,jyx, vehZnshinfo, null,zpurl);
            case "0321"://左灯光工位照片
            case "0352"://右灯光工位照片
                return callCheckVecicleLights(shResourcexx,jyx, vehZnshinfo, zpurl);
            case "0323"://底盘检验照片
                return callCheckChassisInspection(shResourcexx,jyx, vehZnshinfo, zpurl);
            case "0341"://路试行车制动开始照片
                return callCheckRoadTestTravellingBrake(shResourcexx,jyx, vehZnshinfo, zpurl,null);
            case "0343"://路试行车制动结束照片
                return callCheckRoadTestTravellingBrake(shResourcexx,jyx, vehZnshinfo, null,zpurl);
            case "0345"://路试坡度驻车制动照片
                return callCheckRoadTestsLopeBrake(shResourcexx,jyx, vehZnshinfo, zpurl);
            case "0342"://底盘动态结束（年限>10年）
                return callCheckChassisDynamics(shResourcexx,jyx, vehZnshinfo, null, zpurl);
            case "0344"://底盘动态检验开始照片
                return callCheckChassisDynamics(shResourcexx,jyx, vehZnshinfo, zpurl, null);

            case "0322"://一轴制动工位照片
                return callCheckVecicleBrake(shResourcexx,1, jyx, vehZnshinfo, zpurl);
            case "0348"://二轴制动工位照片
                return callCheckVecicleBrake(shResourcexx,2, jyx, vehZnshinfo, zpurl);
            case "0349"://三轴制动工位照片
                return callCheckVecicleBrake(shResourcexx,3, jyx, vehZnshinfo, zpurl);
            case "0350"://四轴制动工位照片
                return callCheckVecicleBrake(shResourcexx,4, jyx, vehZnshinfo, zpurl);
            case "0354"://五轴制动工位照片
                return callCheckVecicleBrake(shResourcexx,5, jyx, vehZnshinfo, zpurl);
            case "0355"://六轴制动工位照片
                return callCheckVecicleBrake(shResourcexx,6, jyx, vehZnshinfo, zpurl);
            case "0357"://二轴加载制动工位照片
                return callCheckVecicleBrake(shResourcexx,2, jyx, vehZnshinfo, zpurl);
            case "0358"://三轴加载制动工位照片
                return callCheckVecicleBrake(shResourcexx,3, jyx, vehZnshinfo, zpurl);
            case "0359"://四轴加载制动工位照片
                return callCheckVecicleBrake(shResourcexx,4, jyx, vehZnshinfo, zpurl);
            case "0351"://驻车制动工位照片
            case "A311"://一轴驻车制动工位照片
            case "A312"://二轴驻车制动工位照片
            case "A313"://三轴驻车制动工位照片
            case "A314"://四轴驻车制动工位照片
            case "A315"://五轴驻车制动工位照片
            case "A316":
            case "A317":
                return callCheckVecicleBrake(shResourcexx,0, jyx, vehZnshinfo, zpurl);
            case "0353"://侧滑工位照片
                return callCheckSideslip(shResourcexx,jyx, vehZnshinfo, zpurl);
            case "0360"://外廓尺寸前面照片
            case "0361"://外廓尺寸后面照片
                return callCheckExternalContour(shResourcexx,jyx, vehZnshinfo, zpurl);
            case "0362"://整备质量左前照片
            case "0363"://整备质量右后照片
                return callCheckCurbWeight(shResourcexx,jyx, vehZnshinfo, zpurl);
            case "A202"://送检人身份证
                return null;
            case "A302"://一轴称重工位照片
            case "A303"://二轴称重工位照片
            case "A304"://三轴称重工位照片
            case "A305"://四轴称重工位照片
            case "A306"://五轴称重工位照片
                return callCheckWheelLoad(shResourcexx,jyx, vehZnshinfo, zpurl);
            default:
                log.info("照片种类"+zpzl+"暂无grpc调用,返回null");
        }
        return null;
    }

    /**
     * 车辆外观（左前、右后、左前45度标准照片）
     * @param jyx
     * @param vehZnshinfo 车辆信息
     * @param imageUrl    照片url
     * @return 不通过项和grpc返回（分隔符---） 可能null或""
     */
    private String callCheckAppearance(String jyx, VehZnshinfo vehZnshinfo,String imageUrl) {
        CheckAppearanceRequest checkAppearanceRequest = CheckAppearanceRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())//车辆车牌答案
                .setBrandAnswer(vehZnshinfo.getClpp1())//车辆品牌答案
                .setColorAnswer(vehZnshinfo.getCsys())//车辆颜色答案
                .setJylb(vehZnshinfo.getJylb())//检验类别
                .setCllx(vehZnshinfo.getCllx())//车辆类型
                .setViewType(vehQueuexxb.getZpzl().equals("0111") ? CarViewType.FRONTLEFT : CarViewType.BACKRIGHT)
                .addAllItems(Arrays.asList(jyx.split(",")))
                .setSourceImage(imageUrl).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckAppearance(jyx, checkAppearanceRequest);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * Vin车架号 0113
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    private String callCheckVin(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckVinRequest checkVinRequest = CheckVinRequest.newBuilder()
                .setVinAnswer(vehZnshinfo.getClsbdh())
                .setVinImg(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckVin(jyx,vehZnshinfo.getClsbdh(),checkVinRequest);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }
    /**
     * 安全带 0157
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    private String callCheckSeatBelt(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckSeatBeltRequest checkSeatBeltRequest = CheckSeatBeltRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckSeatBelt(jyx,checkSeatBeltRequest);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 机动车牌证申请表 0202
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    private String callCheckLicenseApplicationForm(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckLicenseApplicationFormRequest request = CheckLicenseApplicationFormRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setSourceImage(imageUrl)
                .setVehicleTypeAnswer(vehZnshinfo.getCllx())
                .setOwnerAnswer(vehZnshinfo.getSyr())
                .setPlatesTypeAnswer(vehZnshinfo.getHpzl())
                .setPhoneAnswer(StringUtils.defaultString(vehZnshinfo.getSyrlxdh(),""))
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckLicenseApplicationForm(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 交强险保单 0203
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    private String callCheckInsurancePolicy(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckInsurancePolicyRequest request = CheckInsurancePolicyRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setEngineNumberAnswer(vehZnshinfo.getFdjh()==null?"":vehZnshinfo.getFdjh())
                .setJylb(vehZnshinfo.getJylb())
                .setVinAnswer(vehZnshinfo.getClsbdh())
                .setStartDate(vehZnshinfo.getSxrq()==null?"":sdf.format(vehZnshinfo.getSxrq()))
                .setEndDate(vehZnshinfo.getZzrq()==null?"":sdf.format(vehZnshinfo.getZzrq()))
                .setCurrentDate(sdf.format(new Date()))
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckInsurancePolicy(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 行驶证 0201
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    public String callCheckVehicleLicense(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckVehicleLicenseRequest request = CheckVehicleLicenseRequest.newBuilder()
                .setVinAnswer(vehZnshinfo.getClsbdh())
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setEngineNumberAnswer(vehZnshinfo.getFdjh()==null?"":vehZnshinfo.getFdjh())
                .setVehicleTypeAnswer(vehZnshinfo.getCllx())
                .setLicenseAnswer(StringUtils.isNotBlank(vehZnshinfo.getXszbh())?vehZnshinfo.getXszbh():"")//数据库都为空
                .setIssueDateAnswer(vehZnshinfo.getFzrq()!=null?sdf2.format(vehZnshinfo.getFzrq()):"")//数据库都为空
                .setSourceImage(imageUrl)
                .setOwnerAnswer(StringUtils.isNotBlank(vehZnshinfo.getSyr())?vehZnshinfo.getSyr():"")
                .setIdCardName(StringUtils.isNotBlank(vehZnshinfo.getSjr())?vehZnshinfo.getSjr():"")
                .setCllx(vehZnshinfo.getCllx())
                .addAllItems(Arrays.asList(jyx.split(","))).build();

        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckVehicleLicense(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 行驶证正面 0287
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    public String callCheckVehicleLicenseRec(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckVehicleLicenseRecRequest request = CheckVehicleLicenseRecRequest.newBuilder()
                .setVinAnswer(vehZnshinfo.getClsbdh())
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setLicenseNumberAnswer(StringUtils.isNotBlank(vehZnshinfo.getXszbh())?vehZnshinfo.getXszbh():"")//数据库都为空
                .setVehicleTypeAnswer(vehZnshinfo.getCllx())
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();

        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckVehicleLicenseRec(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 机动车安全技术检验报告 0204
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    private String callCheckInspectionReport(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckInspectionReportRequest request = CheckInspectionReportRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setVinAnswer(vehZnshinfo.getClsbdh())
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckInspectionReport(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 尾气单1 0296
     * @param jyx
     * @param znshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    private String callCheckExhaustDetectionReport1(ShResourcexx shResourcexx,String jyx, VehZnshinfo znshinfo, String imageUrl) {
        CheckExhaustDetectionReportRequest request = CheckExhaustDetectionReportRequest.newBuilder()
                .setSourceImage1(imageUrl)
                .setPlateAnswer(znshinfo.getHphm())
                .setVinAnswer(znshinfo.getClsbdh())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckExhaustDetectionReport(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }
    /**
     * 尾气单2 0295
     * @param jyx
     * @param znshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    private String callCheckExhaustDetectionReport2(ShResourcexx shResourcexx,String jyx, VehZnshinfo znshinfo, String imageUrl) {
        CheckExhaustDetectionReportRequest request = CheckExhaustDetectionReportRequest.newBuilder()
                .setSourceImage2(imageUrl)
                .setPlateAnswer(znshinfo.getHphm())
                .setVinAnswer(znshinfo.getClsbdh())
                .setVinCompareThreshold(compareThreshold)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckExhaustDetectionReport(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 左、右灯光 0321 0352
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    private String callCheckVecicleLights(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckVecicleLightsRequest request = CheckVecicleLightsRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setSourceImage(imageUrl)
                .setColorAnswer(vehZnshinfo.getCsys())
                .setCllx(vehZnshinfo.getCllx())
                .setJylb(vehZnshinfo.getJylb())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckVecicleLights(jyx,vehZnshinfo.getHphm(), request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 一轴、二轴（平板制动）、 一轴、二轴（滚筒制动）、驻车制动 0322 0348 0351
     * @param brakeType 制动类型 1 一轴制动， 2 二轴制动， 3 驻车制动
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    private String callCheckVecicleBrake(ShResourcexx shResourcexx,Integer brakeType,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckVecicleBrakeRequest request = CheckVecicleBrakeRequest.newBuilder()
                .setBrakeType(brakeType)
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setJylb(vehZnshinfo.getJylb())
                .setSourceImage(imageUrl)
                .setColorAnswer(vehZnshinfo.getCsys())
                .setCllx(vehZnshinfo.getCllx())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckVecicleBrake(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 底盘检验 0323
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    private String callCheckChassisInspection(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckChassisInspectionRequest request = CheckChassisInspectionRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setCllx(vehZnshinfo.getCllx())
                .setJylb(vehZnshinfo.getJylb())
                .setSourceImage(imageUrl)
                .setCllx(vehZnshinfo.getCllx())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckChassisInspection(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 底盘动态(开始、结束) 0344 0342
     * @param jyx
     * @param vehZnshinfo
     * @param beginImageUrl
     * @param endImageUrl
     * @return 不通过项 可能null或""
     */
    private String callCheckChassisDynamics(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String beginImageUrl, String endImageUrl) {
        CheckChassisDynamicsRequest request = null;
        //底盘动态结束
        if (beginImageUrl == null){
            request = CheckChassisDynamicsRequest.newBuilder()
                    .setPlateAnswer(vehZnshinfo.getHphm())
                    .setSourceEndImage(endImageUrl)
                    .setJylb(vehZnshinfo.getJylb())
                    .setCllx(vehZnshinfo.getCllx())
                    .addAllItems(Arrays.asList(jyx.split(","))).build();
        }
        //底盘动态开始
        if (endImageUrl == null){
            request = CheckChassisDynamicsRequest.newBuilder()
                    .setPlateAnswer(vehZnshinfo.getHphm())
                    .setJylb(vehZnshinfo.getJylb())
                    .setCllx(vehZnshinfo.getCllx())
                    .setSourceBeginImage(beginImageUrl)
                    .addAllItems(Arrays.asList(jyx.split(","))).build();
        }
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckChassisDynamics(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 委托书 0208
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return 不通过项 可能null或""
     */
    private String callCheckAttorneyLetter(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckAttorneyLetterRequest request = CheckAttorneyLetterRequest.newBuilder()
                .setSourceImage(imageUrl)
                .setVinAnswer(vehZnshinfo.getClsbdh())
                .setJylb(vehZnshinfo.getJylb())
                .setPlateNumberAnswer(vehZnshinfo.getHphm())
                .setPlateNumberAnswer(vehZnshinfo.getHphm())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckAttorneyLetter(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 安全技术检验表人工部分 0212 0213
     * @param jyx
     * @param imageUrl1
     * @param imageUrl2
     * @return 不通过项 可能null或""
     */
    private String callCheckInspectionFormManual(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo, String imageUrl1, String imageUrl2) {
        CheckInspectionFormManualRequest request = CheckInspectionFormManualRequest.newBuilder()
                .setSourceImage(imageUrl1==null?"":imageUrl1)
                .setSecondImage(imageUrl2==null?"":imageUrl2)
                .setPlateNumberAnswer(vehZnshinfo.getHphm())
                .setSerialAnswer(vehZnshinfo.getLsh())
                .setJylb(vehZnshinfo.getJylb())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckInspectionFormManual(jyx, vehZnshinfo.getJyxm(),request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 身份证 A202
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return
     */
    private String callCheckIdentificationCard(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckIdentificationCardRequest request = CheckIdentificationCardRequest.newBuilder()
                .setSourceImage(imageUrl)
                //.setIdCardNameAnswer(vehZnshinfo.getSyr())
                //.setIdCardNumberAnswer()
                .setCurrentDate(sdf.format(new Date()))
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckIdentificationCard(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 改装气罐 无
     * @param jyx
     * @param imageUrl
     * @return
     */
    private String callCheckGasTank(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo,String imageUrl){
        CheckGasTankRequest request = CheckGasTankRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckGasTank(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 0132 发动机舱自动灭火装置
     * @param jyx
     * @param imageUrl
     * @return
     */
    private String callCheckFireExtinguisher(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo,String imageUrl){
        CheckFireExtinguisherRequest request = CheckFireExtinguisherRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckFireExtinguisher(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 安全锤 0117
     * @param jyx
     * @param imageUrl
     * @return
     */
    private String callCheckEmergencyHammer(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo,String imageUrl){
        CheckEmergencyHammerRequest request = CheckEmergencyHammerRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckEmergencyHammer(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 行驶记录装置 0118
     * @param jyx
     * @param imageUrl
     * @return
     */
    private String callCheckDriverRecorder(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo,String imageUrl){
        CheckDriverRecorderRequest request = CheckDriverRecorderRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckDriverRecorder(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 防抱死制动装置 0134
     * @param jyx
     * @param imageUrl
     * @return
     */
    private String callCheckAntilockBrakeSystem(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo,String imageUrl){
        CheckAntilockBrakeSystemRequest request = CheckAntilockBrakeSystemRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckAntilockBrakeSystem(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 轮胎规格 '0136', '0152', '0153', '0154', '0155', '0156'
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return
     */
    private String callCheckTyreSpecification(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo,String imageUrl){
        CheckTyreSpecificationRequest request = CheckTyreSpecificationRequest.newBuilder()
                .setSourceImage(imageUrl)
                .setTyreSpecificationAnswer(vehZnshinfo.getLtgg())//轮胎规格答案
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckTyreSpecification(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 行驶证背面 0256 0224
     * @param jyx
     * @param imageUrl
     * @return
     */
    private String callCheckVehicleLicenseBack(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo,String imageUrl){
        CheckVehicleLicenseBackRequest request = CheckVehicleLicenseBackRequest.newBuilder()
                .setSourceImage(imageUrl)
                .setVehicleLicenseColorAnswer(vehZnshinfo.getCsys())//车身颜色答案
                .setVehicleLicenseLogoAnswer(vehZnshinfo.getClpp1())//车标答案
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckVehicleLicenseBack(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 检验表仪器部分 0261
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return
     */
    private String callCheckSafetyTechnicalInspectionFormInstrument(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo, String imageUrl){
        CheckSafetyTechnicalInspectionFormInstrumentRequest request = CheckSafetyTechnicalInspectionFormInstrumentRequest.newBuilder()
                .setSourceImage(imageUrl)
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setVinAnswer(vehZnshinfo.getClsbdh())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckSafetyTechnicalInspectionFormInstrument(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 发动机
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return
     */
    private String callCheckEngineNumber(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo, String imageUrl){
        CheckEngineNumberRequest request = CheckEngineNumberRequest.newBuilder()
                .setEngineImage(imageUrl)//发动机号图像
                //.setRubbingEngineImage()//发动机号拓印膜图像
                .setEngineModelAnswer(vehZnshinfo.getFdjxh())//发动机型号
                .setEngineAnswer(vehZnshinfo.getFdjh())//发动机编号
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckEngineNumber(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    private String callCheckIdentificationCardCopy(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo, String imageUrl){
        CheckIdentificationCardCopyRequest request = CheckIdentificationCardCopyRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckIdentificationCardCopy(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 营业执照
     */
    private String callCheckBusinessLicense(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo, String imageUrl){
        CheckBusinessLicenseRequest request = CheckBusinessLicenseRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckBusinessLicense(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 检查摩托左前右后外观
     */
    private String callCheckMotorAppearance(ShResourcexx shResourcexx,String jyx,VehZnshinfo vehZnshinfo, String imageUrl){
        CheckMotorAppearanceRequest request = CheckMotorAppearanceRequest.newBuilder()
                .setImg(ByteString.copyFrom(urlTobyte(imageUrl,vehZnshinfo,shResourcexx)))
                .setMotorDirection(vehQueuexxb.getZpzl().equals("0111") ? CarViewType.FRONTLEFT : CarViewType.BACKRIGHT)
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setMotorLogoAnswer(vehZnshinfo.getClpp1())
                .setMotorColorAnswer(vehZnshinfo.getCsys())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckMotorAppearance(jyx,request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }


    /**
     * /检查摩托灯光
     */
    private String callCheckMotorLights(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckMotorLightRequest request = CheckMotorLightRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckMotorLights(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }


    /**
     * 检查摩托底盘动态
     */
    private String callCheckMotorChassisDynamics(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckMotorChassisDynamicsRequest request = CheckMotorChassisDynamicsRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckMotorChassisDynamics(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }


    /**
     * 检查摩托一轴、二轴、驻车制动
     */
    private String callCheckMotorBrake(ShResourcexx shResourcexx,Integer brakeType,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckMotorBrakeRequest request = CheckMotorBrakeRequest.newBuilder()
                .setBrakeType(brakeType)
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setSourceImage(imageUrl)
                .setColorAnswer(vehZnshinfo.getCsys())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckMotorBrake(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 检查铭牌
     */
    private String callCheckNameplate(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckNameplateRequest request = CheckNameplateRequest.newBuilder()
                .setCarBrandsAnswer(vehZnshinfo.getClpp1())
                .setCarModelAnswer(vehZnshinfo.getClxh())
                .setEngineModelAnswer(vehZnshinfo.getFdjh())
                .setManufactureDateAnswer(vehZnshinfo.getCcdjrq()==null?"":sdf.format(vehZnshinfo.getCcdjrq()))
                //.setManufactureCountryAnswer("")
                .setDisplacementAnswer(vehZnshinfo.getPl())
                .setTotalQualityAnswer(String.valueOf(Integer.valueOf(vehZnshinfo.getZzl())))
                .setVinAnswer(vehZnshinfo.getClsbdh())
                .setManufactureNameAnswer(vehZnshinfo.getZzcmc())
                .setPassengerNumberAnswer(String.valueOf(vehZnshinfo.getHdzk()))
                .setSourceImage(imageUrl)
                .setVehicleTypeAnswer(vehZnshinfo.getCllx())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckNameplate(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 检车车厢内部
     */
    private String callCheckVanInside(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckVanInsideRequest request = CheckVanInsideRequest.newBuilder()
                .setVehicleTypeAnswer(vehZnshinfo.getCllx())
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckVanInside(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 检查座位数和安全带 0115
     */
    private String callCheckBusInside(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckBusInsideRequest request = CheckBusInsideRequest.newBuilder()
                .setVehicleTypeAnswer(vehZnshinfo.getCllx())
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckBusInside(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 尾气单 0210 0289
     * @param shResourcexx
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return
     */
    private String callCheckExhaustDetectionReport(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl1,String imageUrl2) {
        CheckExhaustDetectionReportRequest request = CheckExhaustDetectionReportRequest.newBuilder()
                .setVehicleTypeAnswer(vehZnshinfo.getCllx())
                .setVinAnswer(vehZnshinfo.getClsbdh())
                .setSourceImage1(imageUrl1==null?"":imageUrl1)
                .setSourceImage2(imageUrl2==null?"":imageUrl2)
                .setJylb(vehZnshinfo.getJylb())
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setFuelTypeAnswer(vehZnshinfo.getRlzl())
                .setHpzl(vehZnshinfo.getHpzl())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckExhaustDetectionReport(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    private String callCheckVehRear(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckVehRearRequest request = CheckVehRearRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setSourceImage(imageUrl)
                .setJylb(vehZnshinfo.getJylb())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckVehRear(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    private String callCheckVehFront(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckVehFrontRequest request = CheckVehFrontRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setSourceImage(imageUrl)
                .setJylb(vehZnshinfo.getJylb())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckVehFront(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 轮重
     * @param shResourcexx
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return
     */
    private String callCheckWheelLoad(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckWheelLoadRequest request = CheckWheelLoadRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setSourceImage(imageUrl)
                .setJylb(vehZnshinfo.getJylb())
                .setCllx(vehZnshinfo.getCllx())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckWheelLoad(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 整备质量
     * @param shResourcexx
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return
     */
    private String callCheckCurbWeight(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckCurbWeightRequest request = CheckCurbWeightRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setSourceImage(imageUrl)
                .setJylb(vehZnshinfo.getJylb())
                .setCllx(vehZnshinfo.getCllx())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckCurbWeight(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 外廓
     * @param shResourcexx
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return
     */
    private String callCheckExternalContour(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckExternalContourRequest request = CheckExternalContourRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setSourceImage(imageUrl)
                .setJylb(vehZnshinfo.getJylb())
                .setCllx(vehZnshinfo.getCllx())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckExternalContour(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 侧滑
     * @param shResourcexx
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return
     */
    private String callCheckSideslip(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckSideslipRequest request = CheckSideslipRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setSourceImage(imageUrl)
                .setJylb(vehZnshinfo.getJylb())
                .setCllx(vehZnshinfo.getCllx())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckSideslip(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 路试行车制动照片
     * @param shResourcexx
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return
     */
    private String callCheckRoadTestTravellingBrake(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String beginImageUrl, String endImageUrl) {
        CheckRoadTestBrakeRequest request = null;
        if (beginImageUrl ==null){
            request = CheckRoadTestBrakeRequest.newBuilder()
                    .setPlateAnswer(vehZnshinfo.getHphm())
                    .setSourceBeginImage(endImageUrl)
                    .setJylb(vehZnshinfo.getJylb())
                    .setCllx(vehZnshinfo.getCllx())
                    .addAllItems(Arrays.asList(jyx.split(","))).build();
        }
        if (endImageUrl == null){
            request = CheckRoadTestBrakeRequest.newBuilder()
                    .setPlateAnswer(vehZnshinfo.getHphm())
                    .setSourceBeginImage(beginImageUrl)
                    .setJylb(vehZnshinfo.getJylb())
                    .setCllx(vehZnshinfo.getCllx())
                    .addAllItems(Arrays.asList(jyx.split(","))).build();
        }
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckRoadTestTravellingBrake(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 路试坡度驻车制动
     * @param shResourcexx
     * @param jyx
     * @param vehZnshinfo
     * @param imageUrl
     * @return
     */
    private String callCheckRoadTestsLopeBrake(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckRoadTestsLopeBrakeRequest request = CheckRoadTestsLopeBrakeRequest.newBuilder()
                .setPlateAnswer(vehZnshinfo.getHphm())
                .setSourceImage(imageUrl)
                .setJylb(vehZnshinfo.getJylb())
                .setCllx(vehZnshinfo.getCllx())
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckRoadTestsLopeBrake(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 教练车副制动踏板 0140
     */
    private String callCheckPassengerPedal(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckPassengerPedalRequest request = CheckPassengerPedalRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckPassengerPedal(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 危险货物运输车标志 0163
     */
    private String callCheckDangerousGoods(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckDangerousGoodsRequest request = CheckDangerousGoodsRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckDangerousGoods(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 发动机灭火器 0169
     */
    private String callCheckCarExtinguisher(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckCarExtinguisherRequest request = CheckCarExtinguisherRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckCarExtinguisher(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 手动机械断电开关 A104
     */
    private String callCheckEmergencySwitch(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckEmergencySwitchRequest request = CheckEmergencySwitchRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckEmergencySwitch(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }


    /**
     * 车内外录像监控系统 0138
     */
    private String callCheckVideoRecordingSystem(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckVideoRecordingSystemRequest request = CheckVideoRecordingSystemRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckVideoRecordingSystem(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 校车停车牌标识 0126
     */
    private String callCheckBusStopSign(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckBusStopSignRequest request = CheckBusStopSignRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckBusStopSign(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 辅助制动系统 0130
     */
    private String callCheckGearLever(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckGearLeverRequest request = CheckGearLeverRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckGearLever(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }

    /**
     * 透光检测仪读数 0175
     */
    private String callCheckInstrument(ShResourcexx shResourcexx,String jyx, VehZnshinfo vehZnshinfo, String imageUrl) {
        CheckInstrumentRequest request = CheckInstrumentRequest.newBuilder()
                .setSourceImage(imageUrl)
                .addAllItems(Arrays.asList(jyx.split(","))).build();
        String btgjyx = "";
        try {
            btgjyx = jianyanService.CheckInstrument(jyx, request);
        }catch (StatusRuntimeException e){
            log.error("grpc调用失败:",e);
            return "-1";
        }
        return btgjyx;
    }





    /**
     * 写进异常信息表
     */
    private void insertShYcrzxxb(String lsh,ShResourcexx shResourcexx,String exInfo){
        ShYcrzxxb shYcrzxxb = new ShYcrzxxb();
        shYcrzxxb.setLsh(lsh);
        shYcrzxxb.setIpdz(shResourcexx.getIpdz());
        shYcrzxxb.setDkh(shResourcexx.getDkh());
        shYcrzxxb.setCjsj(new Date());
        shYcrzxxb.setYcnr(exInfo);
        shYcrzxxbMapper.insert(shYcrzxxb);
    }

    /**
     * url转bytes
     * @param url
     * @return
     */
    public byte[] urlTobyte(String url,VehZnshinfo vehZnshinfo,ShResourcexx shResourcexx){
        byte[] bytes = new byte[0];
        URL ur = null;
        try {
            ur = new URL(url);
        } catch (MalformedURLException e) {
            e.printStackTrace();
            throw new GlobalException("格式错误的URL异常");
        }
        BufferedInputStream in = null;
        ByteArrayOutputStream out = null;
        try {
            in = new BufferedInputStream(ur.openStream());
            out = new ByteArrayOutputStream(1024);
            byte[] temp = new byte[1024];
            int size = 0;
            while ((size = in.read(temp)) != -1) {
                out.write(temp, 0, size);
            }
        }
        catch (Exception e) {
            log.error("照片地址："+url+"可能访问出错！-->",e);
            //todo 清除该lsh作业的数据，并将车辆的yczt置为1
            synchronized (WorkCustomer.class){
                vehQueuexxbService.delWork(vehZnshinfo.getLsh(),null);
                vehZnshinfo.setYczt("1");//置为异常状态
                vehZnshinfoService.updateVehZnshinfo(vehZnshinfo);
                //将服务器改为空闲状态
                shResourcexx.setSfkx("1");
                shResourcexxService.updateResourcexx(shResourcexx);
                return bytes;
            }
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
                return bytes;
            }
        }
        byte[] content = out.toByteArray();

        if (out!=null) {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return content;
    }

    /**
     * 处理服务器挂了之后
     * @param vehQueuexxb
     * @param shResourcexx
     */
    void todoServiceExCeption(VehQueuexxb vehQueuexxb,ShResourcexx shResourcexx){
        synchronized (WorkCustomer.class){
            //算法服务器挂了，将该算法服务器zt改成异常，该条作业审核状态重置为0，已让它下次能重新审
            shResourcexx.setZt("0");//异常
            shResourcexxService.updateResourcexx(shResourcexx);
            vehQueuexxb.setZt("0");//未审核
            vehQueuexxbService.updateVehQueuexxb(vehQueuexxb);
        }
    }

}